<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Knowledge Graph</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      margin: 0;
      padding: 0;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: flex-start;
      height: 100vh;
      overflow: hidden;
    }

    #graph-container {
      width: calc(100%);
      height: calc(100vh - 100px); /* 减去标题和搜索栏的高度 */
      border: 1px solid #ccc;
      margin: 20px 0;
      position: relative;
    }

    #details-container {
      position: fixed;
      top: 50%;
      left: 20px;
      transform: translateY(-50%);
      width: 300px;
      padding: 10px;
      border: 1px solid #ddd;
      border-radius: 5px;
      background: #f9f9f9;
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    }

    #details-container h2 {
      margin: 0 0 10px;
    }

    #details-container ul {
      list-style: none;
      padding-left: 0;
    }

    #details-container ul li {
      margin-bottom: 5px;
    }

    .node {
      cursor: pointer;
      transition: stroke 0.3s ease;
    }

    .node.highlight {
      stroke: orange;
      stroke-width: 3px;
    }

    #form-container {
      position: fixed;
      top: 20px;
      right: 20px;
      width: 300px;
      padding: 10px;
      border: 1px solid #ddd;
      border-radius: 5px;
      background: #f9f9f9;
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    }

    #form-container h2 {
      margin: 0 0 10px;
    }

    label {
      display: block;
      margin: 10px 0 5px;
    }

    input, select, button {
      width: 100%;
      padding: 8px;
      margin-bottom: 10px;
      border: 1px solid #ccc;
      border-radius: 4px;
    }

    button {
      background: #007BFF;
      color: #fff;
      border: none;
      cursor: pointer;
    }

    button:hover {
      background: #0056b3;
    }

    #search-container input {
      width: calc(100% - 100px);
      display: inline-block;
      padding: 8px;
    }

    #search-container button {
      width: 80px;
      display: inline-block;
      background-color: #007BFF;
      color: #fff;
      padding: 8px;
      border: none;
      border-radius: 4px;
      cursor: pointer;
    }

    #search-container button:hover {
      background-color: #0056b3;
    }

    #modal {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background: rgba(0, 0, 0, 0.5);
      display: flex;
      justify-content: center;
      align-items: center;
      display: none;
    }

    #modal-content {
      background: #fff;
      padding: 20px;
      border-radius: 5px;
      width: 300px;
    }

    #modal-content h2 {
      margin-top: 0;
    }

    #modal-content form {
      margin-top: 10px;
    }

    #modal-content form input {
      width: 100%;
      padding: 8px;
      margin-bottom: 10px;
      border: 1px solid #ccc;
      border-radius: 4px;
    }

    #modal-content form button {
      background: #007BFF;
      color: #fff;
      border: none;
      cursor: pointer;
      padding: 8px;
      border-radius: 4px;
    }

    #modal-content form button:hover {
      background: #0056b3;
    }
  </style>
</head>
<body>
  <h1 style="text-align: center;">《机器学习》知识点整理与展示</h1>
  <div id="search-container">
    <input type="text" id="search-node-name" placeholder="搜索节点名称"><button onclick="searchNode()">搜索</button>
  </div>
  <div id="graph-container"></div>
  <div id="details-container">
    <h2>节点详情</h2>
    <p id="node-name">点击节点查看详情</p>
    <ul id="node-attributes"></ul>
    <button onclick="showModal('add')">添加节点</button>
    <button onclick="showModal('relationship')">添加关系</button>
    <button onclick="showModal('delete')">删除节点</button>
    <button onclick="showModal('update')">更新节点</button>
  </div>

  <div id="modal">
    <div id="modal-content">
      <h2 id="modal-title">添加节点</h2>
      <form id="modal-form">
        <input type="text" id="node-name-input" placeholder="节点名称">
        <input type="text" id="node-type-input" placeholder="节点类型">
        <button type="button" onclick="submitForm()">提交</button>
      </form>
    </div>
  </div>

  <script src="https://d3js.org/d3.v6.min.js"></script>
  <script>
    const GRAPH_API_URL = "http://127.0.0.1:5000/get_graph";
    const NODE_DETAILS_API_URL = "http://127.0.0.1:5000/get_node_details";
    const ADD_NODE_API_URL = "http://127.0.0.1:5000/add_node";
    const ADD_RELATIONSHIP_API_URL = "http://127.0.0.1:5000/add_relationship";
    const DELETE_NODE_API_URL = "http://127.0.0.1:5000//delete_node";
    const DELETE_RELATIONSHIP_API_URL = "http://127.0.0.1:5000/delete_relationship";
    const UPDATE_NODE_API_URL = "http://127.0.0.1:5000/update_node";

    let nodes, links, simulation, svg, g;
    const width = document.getElementById("graph-container").offsetWidth;
    const height = document.getElementById("graph-container").offsetHeight;

    function initGraph() {
      svg = d3.select("#graph-container")
        .append("svg")
        .attr("width", width)
        .attr("height", height)
        .call(d3.zoom().on("zoom", (event) => {
          g.attr("transform", event.transform);
        }))
        .append("g");

      g = svg.append("g");

      fetchGraphData();
    }

    function fetchGraphData() {
      fetch(GRAPH_API_URL)
        .then(response => response.json())
        .then(data => {
          nodes = data.nodes;
          links = data.relationships;

          simulation = d3.forceSimulation(nodes)
            .force("link", d3.forceLink(links).id(d => d.id).distance(150))
            .force("charge", d3.forceManyBody().strength(-400))
            .force("center", d3.forceCenter(width / 2, height / 2));

          renderGraph();
        })
        .catch(error => console.error("Error loading graph data:", error));
    }

    function renderGraph() {
      // 重置图标
      g.selectAll("*").remove();

      const link = g.append("g")
        .attr("class", "links")
        .selectAll("line")
        .data(links)
        .enter()
        .append("line")
        .attr("stroke", "#999")
        .attr("stroke-width", 1.5);

      const node = g.append("g")
        .attr("class", "nodes")
        .selectAll("circle")
        .data(nodes)
        .enter()
        .append("circle")
        .attr("r", 10)
        .attr("fill", "#69b3a2")
        .attr("class", "node")
        .on("click", (event, d) => fetchNodeDetails(d.id));

      const label = g.append("g")
        .attr("class", "labels")
        .selectAll("text")
        .data(nodes)
        .enter()
        .append("text")
        .attr("x", 15)
        .attr("y", 5)
        .text(d => d.label)
        .attr("font-size", "12px")
        .attr("fill", "#333");

      simulation.on("tick", () => {
        link
          .attr("x1", d => d.source.x)
          .attr("y1", d => d.source.y)
          .attr("x2", d => d.target.x)
          .attr("y2", d => d.target.y);

        node
          .attr("cx", d => d.x)
          .attr("cy", d => d.y);

        label
          .attr("x", d => d.x + 10)
          .attr("y", d => d.y + 3);
      });
    }

    function fetchNodeDetails(nodeName) {
      fetch(`${NODE_DETAILS_API_URL}?node_name=${nodeName}`)
        .then(response => response.json())
        .then(data => {
          const attributesList = document.getElementById("node-attributes");
          attributesList.innerHTML = "";
          document.getElementById("node-name").textContent = `节点: ${nodeName}`;
          Object.entries(data.node).forEach(([key, value]) => {
            const li = document.createElement("li");
            li.textContent = `${key}: ${value}`;
            attributesList.appendChild(li);
          });
        });
    }

    function searchNode() {
      const searchName = document.getElementById("search-node-name").value;
      const node = nodes.find(n => n.label === searchName);

      if (node) {
        d3.selectAll(".node").classed("highlight", d => d.label === searchName);
        fetchNodeDetails(searchName);
      } else {
        alert("节点未找到！");
      }
    }

    function showModal(action) {
      const modal = document.getElementById("modal");
      const modalTitle = document.getElementById("modal-title");
      const modalForm = document.getElementById("modal-form");

      modal.style.display = "flex";

      if (action === "add") {
        modalTitle.textContent = "添加节点";
        modalForm.innerHTML = `
          <input type="text" id="node-name-input" placeholder="节点名称">
          <input type="text" id="node-type-input" placeholder="节点类型">
          <input type="text" id="node-id-input" placeholder="节点ID">
          <button type="button" onclick="submitForm('add')">提交</button>
        `;
      }else if(action=="relationship"){
        modalTitle.textContent = "添加关系";
        modalForm.innerHTML = `
          <input type="text" id="node-name-input" placeholder="起始节点名称">
          <input type="text" id="node-name-input2" placeholder="目标节点名称">
          <input type="text" id="node-relation-input" placeholder="节点关系">
          <button type="button" onclick="submitForm('relationship')">提交</button>
        `;
      } else if (action === "delete") {
        modalTitle.textContent = "删除节点";
        modalForm.innerHTML = `
          <input type="text" id="node-name-input" placeholder="节点名称">
          <button type="button" onclick="submitForm('delete')">提交</button>
        `;
      } else if (action === "update") {
        modalTitle.textContent = "更新节点";
        modalForm.innerHTML = `
          <input type="text" id="node-name-input" placeholder="节点名称">
          <input type="text" id="node-type-input" placeholder="节点类型">
          <button type="button" onclick="submitForm('update')">提交</button>
        `;
      }
    }

    function submitForm(action) {
      if (action === "add") {
        const node_name = document.getElementById("node-name-input").value;
        const node_type = document.getElementById("node-type-input").value;
        const node_id = document.getElementById("node-id-input").value;
        fetch(ADD_NODE_API_URL, {
        method: "POST",
        headers: {
            "Content-Type": "application/json"
        },
        body: JSON.stringify({ node_name: node_name, node_type: node_type, node_id: node_id })
        })
        .then(response => {
          if (!response.ok) {
            throw new Error("节点添加失败！");
          }
          return response.json();
        })
       .then(data => {
          alert(data.message);
          location.reload();
        })
        .catch(error => {
          alert(error.message || "节点添加失败！");
          console.error("Error adding node:", error);
        });
      }else if(action === "relationship"){
        const node_name = document.getElementById("node-name-input").value;
        const node2_name = document.getElementById("node-name-input2").value;
        const relation_name = document.getElementById("node-relation-input").value;
        fetch(ADD_RELATIONSHIP_API_URL, {
        method: "POST",
        headers: {
            "Content-Type": "application/json"
        },
        body: JSON.stringify({ node_name: node_name, node2_name: node2_name, relation_name: relation_name })
      })
      .then(response => {
        if (!response.ok) {
            throw new Error("关系添加失败！");
        }
        return response.json();
      })
      .then(data => {
        alert(data.message);
      })
      .catch(error => {
        alert(error.message);
       });
      }else if (action === "delete") {
        const node_name = document.getElementById("node-name-input").value;
          fetch('http://127.0.0.1:5000/delete_node', {
            method: "POST",
            headers: {
              "Content-Type": "application/json"
            },
            body: JSON.stringify({ node_name: node_name })
          })
          .then(response => {
            if (!response.ok) {
            throw new Error("节点删除失败！");
          }
          return response.json();
          })
          .then(data => {
            alert(data.message);
            location.reload();
          })
          .catch(error => {
          alert(error.message || "节点删除失败！");
          console.error("Error deleting node:", error);
          });
      }else if (action === "update") {
        const nodeName = document.getElementById("node-name-input").value;
        const nodeType = document.getElementById("node-type-input").value;
        fetch(UPDATE_NODE_API_URL, {
          method: "POST",
          headers: {
            "Content-Type": "application/json"
          },
          body: JSON.stringify({ name: nodeName, type: nodeType })
        })
          .then(response => response.json())
          .then(data => {
            if (data.success) {
              alert("节点更新成功！");
              location.reload();
            } else {
              alert("节点更新失败！");
            }
          })
          .catch(error => console.error("Error updating node:", error));
      }

      const modal = document.getElementById("modal");
      modal.style.display = "none";
    }

    initGraph();
  </script>
</body>
</html>
